
package com.filetransfer.client;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import com.filetransfer.config.FileClientConfig;
import com.filetransfer.transport.command.FileInfoMessage;
import com.filetransfer.transport.util.FileInfoMessageUtil;
import com.filetransfer.transport.util.XStreamWireFormat;
import com.filetransfer.util.LogUtil;



/**
 * 功能说明: 发送文件执行类<br>
 * 开发人员: hanxuetong <br>
 * 开发时间: 2014-7-25 <br>
 * 审核人员: <br>
 * 相关文档: <br>
 * 修改记录: <br>
 * 修改日期 修改人员 修改说明 <br>
 * ======== ====== ============================================ <br>
 * 
 */
public class SendFileHandle implements Runnable {


	private FileTransferInterface fileTransfer;


	private FileInfoMessage fileInfoMessage;
	
	private FileClientConfig clientConfig;
	
	/**
	 * 
	 * @param fileInfo
	 *            传进来的fileInfo的属性FilePath和md5必须有值
	 * @param wantRelativePath 想保存的文件名路径
	 * @param fileTransfer
	 * @param sendToIp
	 * @param sendToPort
	 */
	/*public SendFileHandle(FileInfo fileInfo, String wantRelativePath,
			FileTransferInterface fileTransfer, String sendToIp,
			Integer sendToPort) {

		transportFileInfo(fileInfo,sendToIp,sendToPort,false);
		fileInfoMessage.setWantRelativePath(wantRelativePath);
		this.fileTransfer = fileTransfer;
	

	}
	*/


	/*public SendFileHandle(FileClientConfig clientConfig,FileInfo fileInfo, String wantRelativePath,
			FileTransferInterface fileTransfer, String sendToIp,
			Integer sendToPort, boolean isTransit) {
		transportFileInfo(fileInfo,sendToIp,sendToPort, isTransit);
		fileInfoMessage.setWantRelativePath(wantRelativePath);
		this.fileTransfer = fileTransfer;
		this.clientConfig=clientConfig;
	}*/
	
	public SendFileHandle(FileClientConfig clientConfig,FileInfoMessage fileInfoMessage,FileTransferInterface fileTransfer){
		
		
		FileInfoMessageUtil.checkFileInfoMessage(fileInfoMessage);
		this.fileInfoMessage=fileInfoMessage;
		this.fileTransfer=fileTransfer;
		this.clientConfig=clientConfig;
	}
	
	

	

	private Socket socket = null;

	// private String ip ="localhost";
	// private int port = 111;

	public void run() {

		System.out.println("开始发送文件:" + fileInfoMessage.getAbsolutePath() + " to "
				+ fileInfoMessage.getSendToIp() + ":" + fileInfoMessage.getSendToPort());
		DataOutputStream dos = null;
		InputStream sockIn = null;
		File file = new File(fileInfoMessage.getAbsolutePath());

		if (createConnection()) {

			try {
				socket.setSoTimeout(clientConfig.getSendTimeout());
				sockIn = socket.getInputStream();
				dos = new DataOutputStream(socket.getOutputStream());

				// String fileMd5=MD5Util.getMD5(file);
			/*	dos.writeUTF(fileInfo.getId());
				dos.writeUTF(SendFileUtil.getPathFileName(sendFilePath,
						file.getAbsolutePath()));
				dos.writeUTF(fileInfo.getMd5());
				long fileSize = file.length();
				if (fileSize != 0) {
					fileSize = 1;
				}
				dos.writeLong(fileSize);
				if (isTransit) {  //是中转传输
					dos.writeUTF(GlobalProperties.TRANSFER_TO_HOST_PARSE_INFO);
				}*/
				dos.writeUTF(XStreamWireFormat.marshalText(fileInfoMessage));

				dos.flush();
				String returnInfo= servInfoBack(sockIn); //反馈的信息:服务端返回信息
				if("startSend".equals(returnInfo))
				{
					sendFile(file, dos, sockIn);
				}else{
					
					System.out.println("传输失败，服务端返回信息:"+returnInfo);
					fileInfoMessage.setReplyInfo(returnInfo);
					fileTransfer.failTransferCallBack(fileInfoMessage);
				}
				

			} catch (Exception e) {
				fileInfoMessage.setReplyInfo(e.getMessage());
				fileTransfer.failTransferCallBack(fileInfoMessage);
				LogUtil.err("发送错误 " + e.getMessage());
			} finally {

				try {
					if (dos != null) {
						dos.close();
					}

				} catch (IOException e1) {
					// e1.printStackTrace();
				}

				try {
					if (sockIn != null) {
						sockIn.close();
					}

				} catch (IOException e1) {
					// e1.printStackTrace();
				}

				try {
					socket.close();
				} catch (IOException e) {
					// e.printStackTrace();
				}

			}
		} else {
			fileInfoMessage.setReplyInfo("创建连接就失败！");
			fileTransfer.failTransferCallBack(fileInfoMessage);
		}

	}

	private void sendFile(File file, DataOutputStream dos, InputStream sockIn)
			throws Exception {
		System.out.println("开始传送文件内容。");
		DataInputStream fis = null;
		String backinfo = "";
		try {
			fis = new DataInputStream(new BufferedInputStream(
					new FileInputStream(file)));

			int read = 0;
			int passedlen = 0;
			long length = file.length(); // 获得要发送文件的长度

			int bufferSize = 8192;
			byte[] buf = new byte[bufferSize];
			while ((read = fis.read(buf)) != -1) {
				passedlen += read;
				System.out.println("已经完成文件 [" + file.getName() + "]百分比: "
						+ passedlen * 100L / length + "%");
				dos.write(buf, 0, read);
			}
			socket.shutdownOutput();

			dos.flush();
			backinfo = servInfoBack(sockIn);
			// socket.shutdownOutput();

		} catch (FileNotFoundException e) {
			throw e;
		} catch (IOException e) {
			throw e;
		} catch (Exception e) {
			throw e;
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}

		}
		fileInfoMessage.setReplyInfo(backinfo);
		if (backinfo.equals("sucess")) {
			System.out.println("单文件 " + fileInfoMessage.getAbsolutePath() + "传输完成!");
			
			fileTransfer.sucessTransferCallBack(fileInfoMessage);
		} else {
			System.out.println("返回接收："+backinfo);
			System.out.println("单文件 " +fileInfoMessage.getAbsolutePath() + "传输失败了!");
			fileTransfer.failTransferCallBack(fileInfoMessage);
		}

	}

	/**
	 * 创建连接
	 * @return
	 */
	private boolean createConnection() {
		try {
			// socket = new
			// Socket(GlobalProperties.SEND_TO_SERVER_IP,GlobalProperties.SEND_TO_SERVER_PORT);
			socket = new Socket(fileInfoMessage.getSendToIp(),fileInfoMessage.getSendToPort());
			System.out.println("连接服务器成功！");
			return true;
		} catch (Exception e) {
			System.out.println("连接服务器失败！");
			return false;
		}
	}
	


	/**
	 * 接收对方传回的信息
	 * @param sockIn
	 * @return
	 * @throws Exception
	 */
	public String servInfoBack(InputStream sockIn) throws Exception // 读取服务端的反馈信息
	{
		// 定义socket输入流
		byte[] bufIn = new byte[1024];
		int lenIn = sockIn.read(bufIn); // 将服务端返回的信息写入bufIn字节缓冲区
		String info = new String(bufIn, 0, lenIn);
		return info;
	}

}
